﻿/***
 * @Description:主要完成定长的环形消息队列的初始化，读取消息队列和发送消息队列
 * @Author: Liverpool
 * @Date: 2024-03-03 15:17:09
 * @LastEditTime: 2024-03-03 16:04:48
 * @LastEditors: Liverpool
 */
#include "fix_queue.h"

/***
 * @description: 对环形定长的消息队列进行初始化
 * @Author: Liverpool
 * @Date: 2024-03-03 16:17:03
 * @return {*} 队列创建过程中的错误，成功就返回没有错误
 * @param {D_FixQueue} *queue 需要初始化的消息队列地址
 * @param {void} **buffer 需要指向处理的消息数组的指针
 * @param {int} size 消息队列的容量
 * @param {D_LockerType} locker_type 锁的类型
 */
net_err_t fix_queue_init(D_FixQueue *queue, void **buffer, int size, D_LockerType locker_type)
{
    queue->size = size; // 队列容量初始化赋值
    // 对消息队列的读取地址，写入地址，元素个数归零
    queue->read_index = 0;
    queue->write_index = 0;
    queue->cnt = 0;
    queue->send_sem = SYS_SEM_INVALID;
    queue->receive_sem = SYS_SEM_INVALID;
    net_err_t err = locker_init(&queue->locker, locker_type); // 初始化消息队列的锁
    if (err < 0)
    {
        debug_error(Debug_Queue, "queue init locker failed!");
        return err;
    }
    queue->send_sem = sys_sem_create(size); // 创建消息队列的发送信号量
    if (queue->send_sem == SYS_SEM_INVALID)
    {
        debug_error(Debug_Queue, "queue create sem failed!");
        err = NET_ERR_SYS;
        goto init_failed;
    }

    queue->receive_sem = sys_sem_create(0); // 创建消息队列的接收信号量
    if (queue->receive_sem == SYS_SEM_INVALID)
    {
        debug_error(Debug_Queue, "queue create sem failed!");
        err = NET_ERR_SYS;
        goto init_failed;
    }
    queue->buffer = buffer;
    return NET_ERR_OK;
init_failed:
    if (queue->send_sem != SYS_SEM_INVALID) // 队列创建失败并且发送信号量创建成功那就需要释放发送信号量
    {
        sys_sem_free(queue->send_sem);
    }
    if (queue->receive_sem != SYS_SEM_INVALID) // 队列创建失败并且接收信号量创建成功那就需要释放接收信号量
    {
        sys_sem_free(queue->receive_sem);
    }
    locker_destroy(&queue->locker); // 因为初始化失败所以需要销毁锁
    return err;
}

/***
 * @description: 向消息队列发送数据
 * @Author: Liverpool
 * @Date: 2024-03-05 01:36:56
 * @return {*} 协议栈的错误类型
 * @param {D_FixQueue} *queue  需要发送的消息队列的地址
 * @param {void} *message 发送的消息的地址
 * @param {int} ms 需要分配进入消息队列的时间
 */
net_err_t fix_queue_send(D_FixQueue *queue, void *message, int ms)
{
    locker_lock(&queue->locker); // 上锁
    if ((ms < 0) && (queue->cnt >= queue->size))
    {
        // 消息队列立马相应并且当前的消息队列的元素个数已经大于容量才会触发消息队列缓存满的错误
        locker_Unlock(&queue->locker); // 解锁
        return NET_ERR_FULL;
    }
    locker_Unlock(&queue->locker); // 解锁
    // 需要对消息队列在解锁的情况下才能等待消息队列信号量的释放，否则容易造成死锁现象
    if (sys_sem_wait(queue->send_sem, ms) < 0)
        return NET_ERR_TIMEOUT;                                                                                       // 等待发送信号量时间过长触发超时错误
    locker_lock(&queue->locker);                                                                                      // 上锁
    queue->buffer[queue->write_index++] = message;                                                                    // 对接收到的消息保存内存地址并且发送索引向后+1
    queue->write_index = (queue->write_index >= queue->size) ? queue->write_index % queue->size : queue->write_index; // 构成环形
    queue->cnt++;
    locker_Unlock(&queue->locker);      // 解锁
    sys_sem_notify(queue->receive_sem); // 释放消息队列可以读取的信号量+1
    return NET_ERR_OK;
}

/***
 * @description: 从消息队列中获取需要处理的消息
 * @Author: Liverpool
 * @Date: 2024-03-05 22:23:54
 * @return {*} 返回消息队列对头消息的内存地址
 * @param {D_FixQueue} *queue 需要读取的消息队列
 * @param {int} ms 获取该消息队列消息等待的时间
 */
void *fix_queue_receive(D_FixQueue *queue, int ms)
{
    locker_lock(&queue->locker); // 上锁
    if ((!queue->cnt) && (ms < 0))
    {
        // 只有当消息队列中没有元素的时候并且读取消息也不要等待
        locker_Unlock(&queue->locker);
        return (void *)0;
    }
    locker_Unlock(&queue->locker); // 解锁
    if (sys_sem_wait(queue->receive_sem, ms) < 0)
    {
        return (void *)0; // 等待信号量超时
    }
    locker_lock(&queue->locker);                      // 上锁
    void *message = queue->buffer[queue->read_index]; // 读取消息地址
    queue->read_index++;
    queue->read_index = (queue->read_index >= queue->size) ? queue->read_index % queue->size : queue->read_index; // 构成环形
    queue->cnt--;                                                                                                 // 消息队列元素个数-1
    locker_Unlock(&queue->locker);                                                                                // 解锁
    sys_sem_notify(queue->send_sem);                                                                              // 释放一个可以发送的信号量
    return message;
}
/***
 * @description: 销毁消息队列
 * @Author: Liverpool
 * @Date: 2024-03-07 01:12:48
 * @return {*}
 * @param {D_FixQueue} *queue 需要销毁的消息队列内存地址
 */
void fix_queue_destroy(D_FixQueue *queue)
{
    locker_destroy(&queue->locker); // 销毁队列锁
    sys_sem_free(queue->send_sem);  // 释放发送信号量和接收信号量
    sys_sem_free(queue->receive_sem);
}
/***
 * @description: 得到消息队列中元素的个数
 * @Author: Liverpool
 * @Date: 2024-03-07 01:14:53
 * @return {*}
 * @param {D_FixQueue} *queue 需要查询的消息队列的内存地址
 */
int fix_queue_get_count(D_FixQueue *queue)
{
    locker_lock(&queue->locker); // 上锁
    int count = queue->cnt;
    locker_Unlock(&queue->locker); // 解锁
    return count;
}